package com.example.filesystem.controller;

import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.filesystem.entity.Result;
import com.example.filesystem.entity.User;
import com.example.filesystem.interceptor.LimitFlowInterceptor;
import com.example.filesystem.service.IDirService;
import com.example.filesystem.service.IUserService;
import com.example.filesystem.util.FileUtil;
import com.example.filesystem.util.JwtUtil;
import com.example.filesystem.util.Md5Util;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

import static com.example.filesystem.config.WebConfig.AVATAR_DIR;
import static com.example.filesystem.interceptor.TokenInterceptor.tokenPrefix;

/**
 * @author bbyh
 * @since 2025-04-27
 */
@RestController
@RequestMapping("/user")
@Slf4j
@Api("/用户接口")
public class UserController {
    @Value("${refreshToken.prefix}")
    private String refreshTokenPrefix;

    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private IUserService userService;
    @Resource
    private IDirService dirService;

    @ApiOperation("用户登录接口")
    @PostMapping("/login")
    public Result login(@RequestBody User userVo) {
        try {
            userVo.setPassword(Md5Util.getPassword(userVo.getPassword(), userVo.getUsername()));
            User user = userService.getUserByUsernameAndPassword(userVo);
            if (user == null) {
                return Result.error(null, "账号或密码错误");
            }

            String token = JwtUtil.getToken(userVo.getUsername());
            String refreshToken = JwtUtil.getToken(userVo.getUsername());
            stringRedisTemplate.opsForValue().set(tokenPrefix + userVo.getUsername(), token, 30, TimeUnit.MINUTES);
            stringRedisTemplate.opsForValue().set(refreshTokenPrefix + userVo.getUsername(), refreshToken, 14, TimeUnit.DAYS);
            JSONObject jsonObject = new JSONObject();
            jsonObject.putOnce("token", token);
            jsonObject.putOnce("refreshToken", refreshToken);
            jsonObject.putOnce("password", userVo.getPassword());
            jsonObject.putOnce("avatarUrl", user.getAvatarUrl());
            return Result.success(jsonObject, "用户登陆成功");
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return Result.error(null, "用户登录接口服务出错");
        }
    }

    @ApiOperation("用户退出登录接口")
    @GetMapping("/logout")
    public Result logout(HttpServletRequest request) {
        try {
            String username = request.getHeader("username");
            stringRedisTemplate.delete(tokenPrefix + username);
            stringRedisTemplate.delete(refreshTokenPrefix + username);
            return Result.success(null, "用户退出登陆成功");
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return Result.error(null, "用户退出登录接口服务出错");
        }
    }

    @ApiOperation("用户头像上传接口")
    @PostMapping("/uploadAvatar")
    public Result uploadAvatar(@RequestBody MultipartFile file, @RequestParam String uuid, HttpServletRequest request) {
        try {
            LimitFlowInterceptor.updateFlow(stringRedisTemplate, request, uuid, (int) file.getSize());
            String originalFilename = file.getOriginalFilename();
            assert originalFilename != null;
            String fileName = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")) + "__" + UUID.randomUUID()
                    + originalFilename.substring(originalFilename.lastIndexOf("."));
            FileUtil.upload(file.getInputStream(), fileName, AVATAR_DIR);

            LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(User::getUsername, request.getHeader("username"));
            User user = userService.getOne(wrapper);
            if (user == null) {
                return Result.error(null, "用户身份不存在，头像上传失败");
            }
            user.setAvatarUrl(fileName);
            userService.update(user, wrapper);

            return Result.success(fileName, "用户头像上传成功");
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return Result.error(null, "用户头像上传接口服务出错");
        }
    }

    @ApiOperation("用户头像获取接口")
    @GetMapping("/getAvatar/{avatarUrl}")
    public void getAvatar(@PathVariable String avatarUrl, @RequestParam String uuid, HttpServletResponse response, HttpServletRequest request) {
        try {
            File file = new File(AVATAR_DIR + avatarUrl);
            if (file.exists()) {
                try (FileInputStream inputStream = new FileInputStream(file)) {
                    int size = inputStream.available();
                    LimitFlowInterceptor.updateFlow(stringRedisTemplate, request, uuid, size);
                    byte[] buf = new byte[size];
                    int read = inputStream.read(buf);
                    ServletOutputStream outputStream = response.getOutputStream();
                    outputStream.write(buf, 0, read);
                    outputStream.flush();
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            Result.writeResult(response, "用户头像获取接口服务出错");
        }
    }

    @ApiOperation("验证用户token接口")
    @GetMapping("/verifyToken")
    public Result verifyToken(HttpServletRequest request) {
        try {
            String username = request.getHeader("username");
            String token = request.getHeader("token");
            String refreshToken = request.getHeader("refreshToken");
            if (username == null || token == null || refreshToken == null) {
                return Result.error(null, "用户token验证不通过");
            }

            if (token.equals(stringRedisTemplate.opsForValue().get(tokenPrefix + username))) {
                return Result.success(token, "用户token验证通过");
            }
            if (refreshToken.equals(stringRedisTemplate.opsForValue().get(refreshTokenPrefix + username))) {
                try {
                    JwtUtil.verify(refreshToken, username);
                } catch (Exception e) {
                    return Result.error(null, "用户token验证不通过");
                }
                String newToken = JwtUtil.getToken(username);
                stringRedisTemplate.opsForValue().set(tokenPrefix + username, newToken, 30, TimeUnit.MINUTES);
                return Result.success(newToken, "用户token验证通过");
            }

            return Result.error(null, "用户token验证不通过");
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return Result.error(null, "验证用户token接口服务出错");
        }
    }

    @ApiOperation("用户创建接口")
    @PostMapping("/register")
    public Result register(@RequestBody User userVo) {
        try {
            userVo.setPassword(Md5Util.getPassword(userVo.getPassword(), userVo.getUsername()));
            User user = userService.getUserByUsernameAndPassword(userVo);
            if (user != null) {
                return Result.error(null, "该用户已存在");
            }

            user = new User();
            user.setUsername(userVo.getUsername());
            user.setPassword(userVo.getPassword());
            user.setAvatarUrl("");
            user.setCreateTime(LocalDateTime.now());
            userService.save(user);
            dirService.initRootDir(user.getUsername());

            return Result.success(null, "用户创建成功");
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return Result.error(null, "用户创建接口服务出错");
        }
    }
}
